import re
import sys

class console:
    _addr    = "([^:]*):"
    _portPat = "([0-9]*-[0-9]*|[0-9]*):([^:]*):([0-9]*)$"
    lpat =  re.compile("L " + _portPat)
    llpat = re.compile("L " + _addr + _portPat)
    rpat =  re.compile("R " + _portPat)
    lrpat = re.compile("R " + _addr + _portPat)
    cpat = re.compile("C ([^ ]*)") 
    xpat = re.compile("X ([^ ]*)") 
    qpat = re.compile("Q")
    
    def __init__(self, cin, cout, cerr, tunnel):
        self.cin = cin
        self.cout = cout
        self.cerr = cerr
        self.tunnel = tunnel
        self.idCounter = 0
        self.map = {} # to keep track internal structure with id
        
    def getId(self):
        tmp = self.idCounter
        self.idCounter += 1
        return str(tmp)
    
    def fileno(self):
        "to be selected"
        return self.cin.fileno()
        
    def writeln(self, *args):
        self.cout.write(" ". join(str(x) for x in args) + "\n")
        
    def reply(self):
        id = self.getId()
        self.writeln(id)
        return id
        
    def errln(self, *args):
        self.cerr.write(" ". join(str(x) for x in args) + "\n")
    
    def lForward(self, tuple, id):
        self.tunnel.lForward(tuple, 
                        lambda x: self.forwardCallback(x, id))
    
    def rForward(self, tuple, id): 
        self.tunnel.rForward(tuple, 
                        lambda x: self.forwardCallback(x, id))

    def closeForward(self, targetId, id):
        try:
            forwarder = self.map[targetId] 
            self.tunnel.stopAccept(forwarder, 
                        lambda x: self.closeForwardCallback(x, id))
        except KeyError:
            self.errln("closeForward: cannot find", targetId)
            self.writeln(id, "F")
                                   
    def shutdownForward(self, targetId, id):
        try:
            forwarder = self.map[targetId] 
            self.tunnel.shutdown(forwarder, 
                        lambda x: self.shutdownForwardCallback(x, id))
        except KeyError:
            self.errln("shutdownForward: cannot find", targetId)
            self.writeln(id, "F")

    def quit(self):
        self.tunnel.quit()
    
    def forwardCallback(self, x, id):
        (success, forwarder) = x
        if success:
            self.map[id] = forwarder
            self.writeln(id, "S", forwarder.getPort())
        else:
            self.writeln(id, "F", forwarder)

    def shutdownForwardCallback(self, x, id):
        self.closeForwardCallback(x, id)
            
    def closeForwardCallback(self, (success, mes), id):
        if success:
            self.writeln(id, "S")
        else:
            self.writeln(id, "F", mes)

    def handleIn(self):
        line = self.cin.readline()
        if len(line) == 0:
            return False
        return self.handleLine(line);

    def handleLine(self, line):
        line = line.strip()
        
        m = self.lpat.match(line)
        if  m:
            id = self.reply()
            self.lForward(("", m.groups()[0], m.groups()[1], int(m.groups()[2])), id)
            return True

        m = self.llpat.match(line)
        if  m:
            id = self.reply()
            self.lForward((m.groups()[0], m.groups()[1], m.groups()[2], int(m.groups()[3])), id)
            return True

        m = self.rpat.match(line)
        if  m:
            id = self.reply()
            self.rForward(("localhost", m.groups()[0], m.groups()[1], int(m.groups()[2])), id)
            return True

        m = self.lrpat.match(line)
        if  m:
            id = self.reply()
            addr = m.groups()[0]
            if addr == "":
                addr = "*"
            self.rForward((addr, m.groups()[1], m.groups()[2], int(m.groups()[3])), id)
            return True
        
        m = self.cpat.match(line)
        if m:
            id = self.reply()                 
            self.closeForward(m.groups()[0], id)
            return True
        
        m = self.xpat.match(line)
        if m:
            id = self.reply()
            self.shutdownForward(m.groups()[0], id)
            return True
        
        m = self.qpat.match(line)
        if m:
            self.quit()
        
        self.errln(-1, "unknown command", line)
        return True
    




            
